#ifndef __I264E_H__
#define __I264E_H__

#include <icommon.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

#define I264E_VERSION	"1.0"
#define	I264E_BUILD		"2015.1.1 - 2015.2.1"

#define I264E_KEYINT_MIN_AUTO         0
#define I264E_KEYINT_MAX_INFINITE     (1<<30)

/* Analyse flags */
enum i264e_analyse_partitions {
	I264E_ANALYSE_I4x4       = 0x0001,  /* Analyse i4x4 */
	I264E_ANALYSE_I8x8       = 0x0002,  /* Analyse i8x8 (requires 8x8 transform) */
	I264E_ANALYSE_PSUB16x16  = 0x0010,  /* Analyse p16x8, p8x16 and p8x8 */
	I264E_ANALYSE_PSUB8x8    = 0x0020,  /* Analyse p8x4, p4x8, p4x4 */
	I264E_ANALYSE_BSUB16x16  = 0x0100,  /* Analyse b16x8, b8x16 and b8x8 */
};

enum i264e_mv_pred {
	I264E_DIRECT_PRED_NONE        = 0,
	I264E_DIRECT_PRED_SPATIAL     = 1,
	I264E_DIRECT_PRED_TEMPORAL    = 2,
	I264E_DIRECT_PRED_AUTO        = 3,
};

enum i264e_me_method {
	I264E_ME_DIA                  = 0,
	I264E_ME_HEX                  = 1,
	I264E_ME_UMH                  = 2,
	I264E_ME_ESA                  = 3,
	I264E_ME_TESA                 = 4,
};

enum i264e_cqm_preset {
	I264E_CQM_FLAT                = 0,
	I264E_CQM_JVT                 = 1,
	I264E_CQM_CUSTOM              = 2,
};

enum i264e_rc_method {
	I264E_RC_CQP                  = 0,
	I264E_RC_CBR                  = 1,
	I264E_RC_VBR                  = 2,
	I264E_RC_SMART                = 3,
    I264E_RC_INV                  = 4,
};

enum i264e_dn_method {
	I264E_DN_NONE				= 0,
	I264E_DN_IP					= 1,
	I264E_DN_II					= 2,
};

enum i264e_aq_mode {
	I264E_AQ_NONE                 = 0,
	I264E_AQ_VARIANCE             = 1,
	I264E_AQ_AUTOVARIANCE         = 2,
};

enum i264e_bframe_adaptive {
	I264E_B_ADAPT_NONE            = 0,
	I264E_B_ADAPT_FAST            = 1,
	I264E_B_ADAPT_TRELLIS         = 2,
};

enum i264e_weighted_pred {
	I264E_WEIGHTP_NONE            = 0,
	I264E_WEIGHTP_SIMPLE          = 1,
	I264E_WEIGHTP_SMART           = 2,
};

enum i264e_weighted_bipred {
	I264E_B_PYRAMID_NONE          = 0,
	I264E_B_PYRAMID_STRICT        = 1,
	I264E_B_PYRAMID_NORMAL        = 2,
};

enum i264e_frame_type {
	I264E_TYPE_AUTO      = 0,
	I264E_TYPE_IDR       = 1,
	I264E_TYPE_I         = 2,
	I264E_TYPE_P         = 3,
	I264E_TYPE_BREF      = 4,
	I264E_TYPE_B         = 5,
	I264E_TYPE_KEYFRAME  = 6,
};

static const char * const i264e_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
static const char * const i264e_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 };
static const char * const i264e_b_pyramid_names[] = { "none", "strict", "normal", 0 };
static const char * const i264e_overscan_names[] = { "undef", "show", "crop", 0 };
static const char * const i264e_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", 0 };
static const char * const i264e_fullrange_names[] = { "off", "on", 0 };
static const char * const i264e_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", 0 };
static const char * const i264e_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316",
                                                    "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", 0 };
static const char * const i264e_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c", 0 };
static const char * const i264e_nal_hrd_names[] = { "none", "vbr", "cbr", 0 };

#define IS_I264E_TYPE_I(x) ((x)==I264E_TYPE_I || (x)==I264E_TYPE_IDR)
#define IS_I264E_TYPE_B(x) ((x)==I264E_TYPE_B || (x)==I264E_TYPE_BREF)

typedef struct i264e i264e_t;

/****************************************************************************
 * NAL structure and functions
 ****************************************************************************/

enum nal_unit_type_e
{
    I264E_NAL_UNKNOWN     = 0,
    I264E_NAL_SLICE       = 1,
    I264E_NAL_SLICE_DPA   = 2,
    I264E_NAL_SLICE_DPB   = 3,
    I264E_NAL_SLICE_DPC   = 4,
    I264E_NAL_SLICE_IDR   = 5,    /* ref_idc != 0 */
    I264E_NAL_SEI         = 6,    /* ref_idc == 0 */
    I264E_NAL_SPS         = 7,
    I264E_NAL_PPS         = 8,
    I264E_NAL_AUD         = 9,
    I264E_NAL_FILLER      = 12,
    /* ref_idc == 0 for 6,9,10,11,12 */
};

enum sei_payload_type_e
{
    I264E_SEI_BUFFERING_PERIOD       = 0,
    I264E_SEI_PIC_TIMING             = 1,
    I264E_SEI_PAN_SCAN_RECT          = 2,
    I264E_SEI_FILLER                 = 3,
    I264E_SEI_USER_DATA_REGISTERED   = 4,
    I264E_SEI_USER_DATA_UNREGISTERED = 5,
    I264E_SEI_RECOVERY_POINT         = 6,
    I264E_SEI_DEC_REF_PIC_MARKING    = 7,
    I264E_SEI_FRAME_PACKING          = 45,
};

enum nal_priority_e
{
    I264E_NAL_PRIORITY_DISPOSABLE = 0,
    I264E_NAL_PRIORITY_LOW        = 1,
    I264E_NAL_PRIORITY_HIGH       = 2,
    I264E_NAL_PRIORITY_HIGHEST    = 3,
};

/* The data within the payload is already NAL-encapsulated; the ref_idc and type
 * are merely in the struct for easy access by the calling application.
 * All data returned in an i264e_nal_t, including the data in p_payload, is no longer
 * valid after the next call to i264e_encoder_encode.  Thus it must be used or copied
 * before calling i264e_encoder_encode or i264e_encoder_headers again.
 */
typedef struct i264e_nal {
    int i_ref_idc;  /* nal_priority_e */
    int i_type;     /* nal_unit_type_e */
    int b_long_startcode;

    /* Size of payload (including any padding) in bytes. */
    int     i_payload;
    /* If param->b_annexb is set, Annex-B bytestream with startcode.
     * Otherwise, startcode is replaced with a 4-byte size.
     * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */
    uint8_t *p_payload;

    /* Size of padding in bytes. */
    int i_padding;
} i264e_nal_t;

typedef struct {
	int			i_dn_type;
	int			i_itype_qp;
	int			i_ptype_qp;
} i264e_denoise_t;

typedef struct i264e_param {
	int			index;
	int			soc;
	int			b_tlb;
	int			b_use_phy;
	int			b_user_fenc;			/* whether use user buf to hw encode */
	int			b_user_nalbuffer;		/* whether use user nal buf  */
	int         b_open_coop;	 /* open cooperator mode */
	int         b_use_dn;		/* use denoise mode */
	int         b_use_ncu;		/* use denoise mode */
	int			i_devid;
	int         i_threads;           /* encode multiple frames in parallel */
	int         i_gop;           /* gop size */
	int			b_mref;			/* use multiple(2) frames to encode */
	int			b_buf_share;	/* whether to use buf share between temporal reference and decoder */

	/* Video Properties */
	int         i_width;
	int         i_height;
	int         i_csp;         /* CSP of encoded bitstream */
	int			i_profile;
	int         i_level_idc;

	/* VUI */
	struct
	{
		/* they will be reduced to be 0 < x <= 65535 and prime */
		int         i_sar_height;
		int         i_sar_width;

		int         i_overscan;    /* 0=undef, 1=no overscan, 2=overscan */

		/* see h264 annex E for the values of the following */
		int         i_vidformat;
		int         b_fullrange;
		int         i_colorprim;
		int         i_transfer;
		int         i_colmatrix;
		int         i_chroma_loc;    /* both top & bottom */
	} vui;

    /* Bitstream parameters */
    int         i_dpb_size;         /* Force a DPB size larger than that implied by B-frames
									   and reference frames. Useful in combination with
									   interactive error resilicodece. */
    int         i_frame_reference;  /* Maximum number of reference frames */
	int         b_deblocking_filter;
	int         i_deblocking_filter_alphac0;    /* [-6, 6] -6 light filter, 6 strong */
	int         i_deblocking_filter_beta;       /* [-6, 6]  idem */

	int         b_cabac;
	int         i_cabac_init_idc;

    /* Encoder analyser parameters */
    struct
    {
        int          i_weighted_pred; /* weighting for P-frames */
        int          b_transform_8x8;
        int          i_chroma_qp_offset;
		int          i_mv_range; /* maximum length of a mv (in pixels). -1 = auto, based on level */
        int          i_subpel_refine; /* subpixel motion estimation quality */
        int          b_fast_mvp; /* open fast mvp */
        int          b_psnr;    /* compute and print PSNR stats */
        int          b_ssim;    /* compute and print SSIM stats */
    } analyse;

	/* skip control parameters */
	c_high_skip_t	hskip;
	int	i_max_skip_type;

	/* Rate control parameters */
	struct
	{
		int         i_rc_method;    /* I264E_RC_* */

		int         i_qp_constant;  /* 0 to (51 + 6*(i264e_bit_depth-8)). 0=lossless */
        int         i_qp_min;       /* min allowed QP value */
        int         i_qp_max;       /* max allowed QP value */
        float       f_rate_tolerance;
        float       f_ip_factor;
        float       f_pb_factor;

		int			i_bitrate;

		int			i_fps_min;		/* Scenecuts closer together than this are coded as I, not IDR. */
		int			i_fps_max;		/* Force an IDR keyframe at this interval */
		int			i_biaslvl;
        int         i_qp_step;      /* max QP step between frames */
		int			i_gop_qp_step;	/* max QP step between gop frames */
		bool		b_adaptive_mode;
		bool		b_gop_relation;

		int			i_static_time;
		int			i_max_bitrate;
		int			i_change_pos;
        int         i_quality_level;
		float		i_trigger_level;
		int			i_new_qp_max_thr;
        int         b_enable_mbrc;
        int         b_enable_change_ref;
	} rc;

    c_superfrm_param_t superFrm;

	i264e_denoise_t denoise;

	/* roi */
	c_roi_t	roi[8];
	/* Cropping Rectangle parameters: added to those implicitly defined by
	   non-mod16 video resolutions. */
	struct
	{
		uint32_t i_left;
		uint32_t i_top;
		uint32_t i_right;
		uint32_t i_bottom;
	} crop;

    /* Muxing parameters */
    int b_repeat_headers;       /* put SPS/PPS before each keyframe */
    int b_annexb;               /* if set, place start codes (4 bytes) before NAL units,
                                 * otherwise place size (4 bytes) before NAL units. */
    int i_sps_id;               /* SPS and PPS id number */
    int b_vfr_input;            /* VFR input.  If 1, use timebase and timestamps for
								   ratecontrol purposes. If 0, use fps only. */
    uint32_t i_fps_num;
    uint32_t i_fps_den;
    uint32_t i_timebase_num;    /* Timebase numerator */
    uint32_t i_timebase_den;    /* Timebase denominator */

    /* Log */
    void        (*pf_log)(const char *module, int i_level, const char *psz, va_list);
    char        *module;
    int         i_log_level;

	int i_slice_count;       /* Number of slices per frame: forces rectangular slices. */

	/* buf managememt */
	/* must be vitural addr */
	void *(*ckmalloc)(int index, int size, int align);
	void (*ckfree)(int index, void *);
	intptr_t (*ckvirt_to_phys)(intptr_t vaddr);
	intptr_t (*ckphys_to_virt)(intptr_t paddr);

	/* Private tlb */
	int private_tlb_flag;
	uint32_t private_tlb_vbase;
	uint32_t private_tlb_pbase;

	/* watermark*/
	int b_fisheye;

	/* other param */
	int		b_bs_save;
	int		b_ref_save;
	int		b_enc_save;
	int		b_dec_save;
} i264e_param_t;

void i264e_nal_encode( i264e_t *h, uint8_t *dst, i264e_nal_t *nal );

/****************************************************************************
 * H.264 level restriction information
 ****************************************************************************/

typedef struct {
    int level_idc;
    int mbps;        /* max macroblock processing rate (macroblocks/sec) */
    int frame_size;  /* max frame size (macroblocks) */
    int dpb;         /* max decoded picture buffer (mbs) */
    int bitrate;     /* max bitrate (kbit/sec) */
    int cpb;         /* max vbv buffer (kbit) */
    int mv_range;    /* max vertical mv component range (pixels) */
    int mvs_per_2mb; /* max mvs per 2 consecutive mbs. */
    int slice_rate;  /* ?? */
    int mincr;       /* min compression ratio */
    int bipred8x8;   /* limit bipred to >=8x8 */
    int direct8x8;   /* limit b_direct to >=8x8 */
    int frame_only;  /* forbid interlacing */
} i264e_level_t;

/* all of the levels defined in the standard, terminated by .level_idc=0 */
extern const i264e_level_t i264e_levels[];

typedef struct
{
    /* All arrays of data here are ordered as follows:
     * each array contains one offset per macroblock, in raster scan order.  In interlaced
     * mode, top-field MBs and bottom-field MBs are interleaved at the row level.
     * Macroblocks are 16x16 blocks of pixels (with respect to the luma plane).  For the
     * purposes of calculating the number of macroblocks, width and height are rounded up to
     * the nearest 16.  If in interlaced mode, height is rounded up to the nearest 32 instead. */

    /* In: an array of quantizer offsets to be applied to this image during encoding.
     *     These are added on top of the decisions made by i264e.
     *     Offsets can be fractional; they are added before QPs are rounded to integer.
     *     Adaptive quantization must be enabled to use this feature.  Behavior if quant
     *     offsets differ between encoding passes is undefined. */
    float *quant_offsets;
    /* In: optional callback to free quant_offsets when used.
     *     Useful if one wants to use a different quant_offset array for each frame. */
    void (*quant_offsets_free)( void* );

    /* In: optional array of flags for each macroblock.
     *     Allows specifying additional information for the encoder such as which macroblocks
     *     remain unchanged.  Usable flags are listed below.
     *     i264e_param_t.analyse.b_mb_info must be set to use this, since i264e needs to track
     *     extra data internally to make full use of this information.
     *
     * Out: if b_mb_info_update is set, i264e will update this array as a result of encoding.
     *
     *      For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded
     *      pixels have changed.  This can be useful for e.g. noting which areas of the
     *      frame need to actually be blitted. Note: this intentionally ignores the effects
     *      of deblocking for the current frame, which should be fine unless one needs exact
     *      pixel-perfect accuracy.
     *
     *      Results for MBINFO_CONSTANT are currently only set for P-frames, and are not
     *      guaranteed to enumerate all blocks which haven't changed.  (There may be false
     *      negatives, but no false positives.)
     */

    /* Out: SSIM of the the frame luma (if i264e_param_t.b_ssim is set) */
    double f_ssim;
    /* Out: Average PSNR of the frame (if i264e_param_t.b_psnr is set) */
    double f_psnr_avg;
    /* Out: PSNR of Y, U, and V (if i264e_param_t.b_psnr is set) */
    double f_psnr[3];

    /* Out: Average effective CRF of the encoded frame */
    double f_crf_avg;
} i264e_image_properties_t;

typedef struct
{
    double cpb_initial_arrival_time;
    double cpb_final_arrival_time;
    double cpb_removal_time;

    double dpb_output_time;
} i264e_hrd_t;

/* Arbitrary user SEI:
 * Payload size is in bytes and the payload pointer must be valid.
 * Payload types and syntax can be found in Annex D of the H.264 Specification.
 * SEI payload alignment bits as described in Annex D must be included at the
 * end of the payload if needed.
 * The payload should not be NAL-encapsulated.
 * Payloads are written first in order of input, apart from in the case when HRD
 * is enabled where payloads are written after the Buffering Period SEI. */
typedef struct
{
    int payload_size;
    int payload_type;
    uint8_t *payload;
} i264e_sei_payload_t;

typedef struct
{
    int num_payloads;
    i264e_sei_payload_t *payloads;
    /* In: optional callback to free each payload AND i264e_sei_payload_t when used. */
    void (*sei_free)(void*);
} i264e_sei_t;

typedef struct i264e_pic {
    /* In: force quantizer for != I264E_QP_AUTO */
    int     i_qpplus1;
    /* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1.
     *     use pic_struct_e for pic_struct inputs
     * Out: pic_struct element associated with frame */
    int     i_pic_struct;
    /* Out: whether this frame is a keyframe.  Important when using modes that result in
     * SEI recovery points being used instead of IDR frames. */
    int     b_force_idr;
    /* In: user pts, Out: pts of encoded picture (user)*/
    int64_t i_pts;
    /* Out: frame dts. When the pts of the first frame is close to zero,
     *      initial frames may have a negative dts which must be dealt with by any muxer */
    int64_t i_dts;
	int64_t timestamp;
    /* In: custom encoding parameters to be set from this frame forwards
           (in coded order, not display order). If NULL, continue using
           parameters from the previous frame.  Some parameters, such as
           aspect ratio, can only be changed per-GOP due to the limitations
           of H.264 itself; in this case, the caller must force an IDR frame
           if it needs the changed parameter to apply immediately. */
    c_img_t img;
	/* PadFrame Private tlb img */
    c_img_t pad_img;
	c_fsktype_t fsktype;
    /* In: optional information to modify encoder decisions for this frame
     * Out: information about the encoded frame */
    i264e_image_properties_t prop;
    /* Out: HRD timing information. Output only when i_nal_hrd is set. */
    i264e_hrd_t hrd_timing;
    /* In: arbitrary user SEI (e.g subtitles, AFDs) */
    i264e_sei_t extra_sei;
    /* private user data. copied from input to output frames. */
    void *opaque;
	uint8_t **nals_buffer;
	int nals_buffer_size;
} i264e_pic_t;

enum i264e_rcfg_type {
	I264E_RCFG_C2G_ID	= 0,
	I264E_RCFG_CUT_ID,
	I264E_RCFG_ROI_ID,
	I264E_RCFG_RC_ID,
	I264E_RCFG_RC_TRIG_ID,
	I264E_RCFG_FPS_ID,
	I264E_RCFG_ENIDR_ID,
	I264E_RCFG_GOP_ID,
	I264E_RCFG_DN_ID,
	I264E_RCFG_HSKIP_ID,
	I264E_RCFG_BENHANCE_ID,
	I264E_RCFG_MBRC_ID,
	I264E_RCFG_CHGREF_ID,
	I264E_RCFG_SUPER_ID,
	I264E_RCFG_TRANS_ID,
    I264E_RCFG_QPGMODE_ID,
	I264E_RCFG_RCFILE_ID,
};


typedef struct i264e_rcfg_c2g_param {
	int on;
} i264e_rcfg_c2g_param_t;

typedef struct i264e_rcfg_cut_param {
	int on;
	int start_mb_x;
	int mb_width;
	int start_mb_y;
	int mb_height;
} i264e_rcfg_cut_param_t;

typedef struct i264e_rcfg_roi_param {
	int idx;
	c_roi_t roi;
} i264e_rcfg_roi_param_t;

typedef struct i264e_rcfg_rc_param {
	int on;
	int rc_method;
	int qp;
	int max_qp;
	int min_qp;
	int bitrate;
	int	biaslvl;
	int qp_step;
	int	gop_qp_step;
	bool adaptive_mode;
	bool gop_relation;
	int static_time;
	int max_bitrate;
	int change_pos;
    int quality_level;
} i264e_rcfg_rc_param_t;

typedef struct i264e_rcfg_rc_trig_param {
	float	trigger_level;
	int		new_qp_max_thr;
} i264e_rcfg_rc_trig_param_t;

typedef struct i264e_rcfg_fps_param {
	int on;
	uint32_t i_fps_num;
	uint32_t i_fps_den;
} i264e_rcfg_fps_param_t;

typedef struct i264e_rcfg_enidr_param {
	int on;
} i264e_rcfg_enidr_param_t;

typedef struct i264e_rcfg_gop_param {
	int gopsize;
} i264e_rcfg_gop_param_t;

extern i264e_t *i264e_init(i264e_param_t *param);
extern int i264e_encode(i264e_t *h, i264e_pic_t *pic_in);
extern void i264e_get_bitstream_cleanup_route(void *h);
extern int i264e_get_bitstream(i264e_t *h, i264e_nal_t **pp_nal, int *pi_nal, i264e_pic_t **pic_in,
		i264e_pic_t **pic_out, void **bshandler, void **handler);
extern int i264e_release_bitstream(i264e_t *h, void *bshandler, void *thandler);
extern void i264e_deinit(i264e_t *h);

extern int i264e_delay_num(i264e_t *h);
extern int i264e_get_param(i264e_t *h, int param_id, void *param);
extern int i264e_set_param(i264e_t *h, int param_id, const void *param);

extern void i264e_param_default(i264e_param_t *param);

#ifdef __cplusplus
}
#endif

#endif /* __I264E_H__ */
